﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using System.IO;
using System.Runtime.Serialization;

namespace MediaRecommender.Model
{
    
    public sealed class MediaCollection : IEnumerable
    {
        private static readonly MediaCollection _instance = new MediaCollection();
        private List<Media> _mediaDatabase;
        private List<AssociatedPerson> _personDatabase;
        private AssociatedPeopleVectorWrapper _associatedPeopleVectorWrap;
        private String FilePath = "c:\\P3Project log folder\\";  // AppDomain.CurrentDomain.BaseDirectory + "\\Db\\";

        //filename bytestreams from serialization is written to.
        private string MediaFilename = "MediaCollection.txt";
        private string AssocFilename = "AssocCollection.txt";
        private string VectorFilename = "VectorCollection.txt";

        private MediaCollection() 
        {
            _mediaDatabase = new List<Media>();
            _personDatabase = new List<AssociatedPerson>();
            _associatedPeopleVectorWrap = new AssociatedPeopleVectorWrapper();
        }

        public static MediaCollection Instance
        {
            get { return _instance; }
        }

        public void Add(Media media)
        {
            if (!_mediaDatabase.Contains(media))
            {
                _mediaDatabase.Add(media);
            }
        }

        public void Add(ICollection<Media> media)
        {
            foreach (var item in media)
            {
                Add(item);
            }
        }

        public bool Remove(Media media)
        {
            if (!_mediaDatabase.Contains(media))
            {
                return false;
            }
            return _mediaDatabase.Remove(media);
        }

        public int CountMedia()
        {
            return _mediaDatabase.Count();
        }

        public Media GetMedia()
        {
            return _mediaDatabase[0];
        }

        public List<Media> GetMedia(Predicate<Media> predicate)
        {
            return _mediaDatabase.FindAll(predicate);
        }

        public List<Media> GetAllMedia()
        {
            return _mediaDatabase;
        }

        public AssociatedPerson ReturnIfInCollection(string name)
        {
            var rtnAssPeople = _personDatabase.Where(x => x.Name == name).ToList();

            if (rtnAssPeople.Count != 0)
                return rtnAssPeople.First();
            return null;
        }

        public void DirectAdd(AssociatedPerson person)
        {
            _personDatabase.Add(person);
        }

        public void AddPerson(AssociatedPerson person)
        {
            if (!_personDatabase.Contains(person))
            {
                _personDatabase.Add(person);
                _associatedPeopleVectorWrap._associatedPeopleVector.Add(0);

                foreach (var user in UserCollection.Instance.GetAllUsers())
                    user.MediaList.AssociatedPeopleVector.Add(0);
            }
        }

        public int CountPeople()
        {
            return _personDatabase.Count;
        }

        public List<AssociatedPerson> ReturnAllPeople()
        {
            return _personDatabase;
        }

        public List<double> ReturnAssociatedPeopleVector()
        {
            return _associatedPeopleVectorWrap._associatedPeopleVector;
        }

        public IEnumerator GetEnumerator()
        {
            return _mediaDatabase.GetEnumerator();
        }

        public void WriteDbToFile()
        {
            ObjectToFile serializer = new ObjectToFile();

            if (!Directory.Exists(FilePath))
            {
                Directory.CreateDirectory(FilePath);
            }            
            serializer.SerializeObject<List<Media>>(FilePath + MediaFilename, _mediaDatabase);
            serializer.SerializeObject<List<AssociatedPerson>>(FilePath + AssocFilename, _personDatabase);
            serializer.SerializeObject<AssociatedPeopleVectorWrapper>(FilePath + VectorFilename, _associatedPeopleVectorWrap);
        }

        public void ReadDbFromFile()
        {
            ObjectToFile serializer = new ObjectToFile();

            if (Directory.Exists(FilePath))
            {
                try
                {
                    _mediaDatabase = serializer.DeSerializeObject<List<Media>>(FilePath + MediaFilename);
                }
                catch (FileNotFoundException)
                {
                }

                try
                {
                    _personDatabase = serializer.DeSerializeObject<List<AssociatedPerson>>(FilePath + AssocFilename);
                }
                catch (FileNotFoundException)
                {
                }
                try
                {
                    _associatedPeopleVectorWrap = serializer.DeSerializeObject<AssociatedPeopleVectorWrapper>(FilePath + VectorFilename);
                }
                catch (FileNotFoundException)
                {
                }
            }
        }
    }

    [Serializable()]
    public class AssociatedPeopleVectorWrapper: ISerializable
    {
        public List<double> _associatedPeopleVector;

        public AssociatedPeopleVectorWrapper()
        {
            _associatedPeopleVector = new List<double>();
        }

        #region Serialization
        private AssociatedPeopleVectorWrapper(SerializationInfo info, StreamingContext ctxt)
        {
            this._associatedPeopleVector = (List<double>)info.GetValue("AssociatedPeopleVector", typeof(List<double>));
        }

        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("AssociatedPeopleVector", this._associatedPeopleVector);
        }
        #endregion
    }
}